package com.lefeng.cockpit.datax.service.impl;

import cn.hutool.core.util.ObjectUtil;
import com.didiglobal.logi.security.common.Result;
import com.didiglobal.logi.security.util.CopyBeanUtil;
import com.google.common.collect.Lists;
import com.lefeng.cockpit.common.bean.dto.datasource.DataSourceDTO;
import com.lefeng.cockpit.common.bean.dto.meta.MetaDTO;
import com.lefeng.cockpit.common.bean.po.datasource.DataSourcePO;
import com.lefeng.cockpit.common.constant.JdbcConstants;
import com.lefeng.cockpit.datax.dao.DataSourceDao;
import com.lefeng.cockpit.datax.service.MetadataService;
import com.lefeng.cockpit.datax.tool.query.BaseQueryTool;
import com.lefeng.cockpit.datax.tool.query.MongoDBQueryTool;
import com.lefeng.cockpit.datax.tool.query.QueryToolFactory;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.ObjectUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.io.IOException;
import java.sql.SQLException;
import java.util.List;
import java.util.Map;

@Service
@Transactional(readOnly = true)
@Slf4j
public class MetadataServiceImpl implements MetadataService {

    @Resource
    private DataSourceDao dataSourceDao;

    private DataSourceDTO getDataSourceDTO(Integer id) {
        DataSourcePO datasource = dataSourceDao.getById(id);
        if (ObjectUtil.isNull(datasource)) {
            return null;
        }
        return CopyBeanUtil.copy(datasource, DataSourceDTO.class);
    }

    @Override
    public Result<List<String>> getDBs(Integer id) throws IOException {
        DataSourceDTO dto = getDataSourceDTO(id);
        if (dto == null) {
            return Result.buildSucc(Lists.newArrayList());
        }
        return Result.buildSucc(new MongoDBQueryTool(dto).getDBNames());
    }

    @Override
    public Result<List<String>> getTables(Integer id, String tableSchema) throws IOException {
        DataSourceDTO dto = getDataSourceDTO(id);
        if (dto == null) {
            return Result.buildSucc(Lists.newArrayList());
        }
        BaseQueryTool queryTool = QueryToolFactory.getByDbType(dto);
        if (JdbcConstants.MONGODB.equals(dto.getDsType())) {
            return Result.buildSucc(new MongoDBQueryTool(dto).getCollectionNames(dto.getDbName()));
        }
        return Result.buildSucc(StringUtils.isBlank(tableSchema) ?
                queryTool.getTableNames() : queryTool.getTableNames(tableSchema));
    }

    @Override
    public Result<List<String>> getTableSchema(Integer id) {
        BaseQueryTool queryTool = getQueryTool(id);
        assert queryTool != null;
        return Result.buildSucc(queryTool.getTableSchema());
    }

    @Override
    public Result<List<String>> getCollectionNames(Integer id, String dbName) throws IOException {
        DataSourceDTO dto = getDataSourceDTO(id);
        if (dto == null) {
            return Result.buildSucc(Lists.newArrayList());
        }
        return Result.buildSucc(new MongoDBQueryTool(dto).getCollectionNames(dbName));
    }

    @Override
    public Result<List<String>> getColumns(Integer id, String tableName) throws IOException {
        DataSourceDTO dto = getDataSourceDTO(id);
        if (ObjectUtils.isEmpty(dto)) {
            return Result.buildSucc(Lists.newArrayList());
        }
        BaseQueryTool queryTool = QueryToolFactory.getByDbType(dto);
        if (JdbcConstants.MONGODB.equals(dto.getDsType().toLowerCase())) {
            return Result.buildSucc(new MongoDBQueryTool(dto).getColumns(tableName));
        }
        return Result.buildSucc(queryTool.getColumnNames(tableName, dto.getDsType().toLowerCase()));
    }

    @Override
    public Result<List<String>> getColumnsByQuerySql(Integer datasourceId, String querySql) throws SQLException {
        BaseQueryTool queryTool = getQueryTool(datasourceId);
        assert queryTool != null;
        return Result.buildSucc(queryTool.getColumnsByQuerySql(querySql));
    }

    @Override
    public Result<Map<String, Object>> getSample(MetaDTO metaDTO) {
        BaseQueryTool queryTool = getQueryTool(metaDTO.getDatabaseSourceId());
        if (ObjectUtils.isEmpty(queryTool)) {
            Result result = new Result();
            result.setCode(1234);
            result.setMessage("不支持的数据库类型");
            return Result.buildFrom(result);
        }
        return Result.buildSucc(queryTool.getSampleData(metaDTO.getTableName()));
    }

    //  ================================================= private ========================================================
    private BaseQueryTool getQueryTool(Integer id) {
        DataSourceDTO dto = getDataSourceDTO(id);
        if (dto == null) {
            return null;
        }
        return QueryToolFactory.getByDbType(dto);
    }

}
